#include "PointCloud.h"
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Point>

PointCloud::PointCloud()
	:mPointList(new osg::Vec3Array)
	, mNormalList(new osg::Vec3Array)
	, mColorList(new osg::Vec4Array)
{
	osg::Geometry::setName("pointcloud");
}

PointCloud::~PointCloud()
{
}

PointLabCore::CLASS_TYPE PointCloud::classID() const
{
	return PointLabCore::CLASS_TYPE::POINT_CLOUD;
}

PointLabCore::Entity* PointCloud::createInstance()
{
	return new PointCloud;
}

bool PointCloud::hasPoint() const
{
	return mPointList->size() > 0;
}

PointLabCore::Uint PointCloud::getPointNum() const
{
	return mPointList->size();
}

void PointCloud::resizePointNum(PointLabCore::Uint num)
{
	mPointList->resizeArray(num);
}

void PointCloud::setPointCoord(PointLabCore::Uint pid, const PointLabCore::Vector3& coord)
{
	mPointList->at(pid) = osg::Vec3(coord.x, coord.y, coord.z);
}

PointLabCore::Vector3 PointCloud::getPointCoord(PointLabCore::Uint pid) const
{
	const osg::Vec3 p = mPointList->at(pid);
	return PointLabCore::Vector3(p.x(), p.y(), p.z());
}

void PointCloud::appendPointCoord(const PointLabCore::Vector3& coord)
{
	mPointList->push_back(osg::Vec3(coord.x, coord.y, coord.z));
}

bool PointCloud::hasNormal() const
{
	return mNormalList->size() > 0;
}

PointLabCore::Uint PointCloud::getNormalNum() const
{
	return mNormalList->size();
}

void PointCloud::resizeNormalNum(PointLabCore::Uint num)
{
	mNormalList->resizeArray(num);
}

void PointCloud::setPointNormal(PointLabCore::Uint pid, const PointLabCore::Vector3& normal)
{
	mNormalList->at(pid) = osg::Vec3(normal.x, normal.y, normal.z);
}

PointLabCore::Vector3 PointCloud::getPointNormal(PointLabCore::Uint pid) const
{
	const osg::Vec3 n = mNormalList->at(pid);
	return PointLabCore::Vector3(n.x(), n.y(), n.z());
}

void PointCloud::appendPointNormal(const PointLabCore::Vector3& normal)
{
	mNormalList->push_back(osg::Vec3(normal.x, normal.y, normal.z));
}

bool PointCloud::hasColor() const
{
	return mColorList->size() > 0;
}

PointLabCore::Uint PointCloud::getColorNum() const
{
	return mColorList->size();
}

void PointCloud::resizeColorNum(PointLabCore::Uint num)
{
	mColorList->resizeArray(num);
}

void PointCloud::setPointColor(PointLabCore::Uint pid, const PointLabCore::Color4& color)
{
	mColorList->at(pid) = osg::Vec4(color.r, color.g, color.b, color.a);
}

PointLabCore::Color4 PointCloud::getPointColor(PointLabCore::Uint pid)
{
	const osg::Vec4 c = mColorList->at(pid);
	return PointLabCore::Color4(c.r(), c.g(), c.b());
}

void PointCloud::appendPointColor(const PointLabCore::Color4& color)
{
	mColorList->push_back(osg::Vec4(color.r, color.g, color.b, color.a));
}

void PointCloud::clearAll()
{
	mPointList->clear();
	mNormalList->clear();
	mColorList->clear();
}

void PointCloud::prepareDisplayForRefresh()
{
	setVertexArray(mPointList);
	if (hasColor())
	{
		setColorArray(mColorList);
		setColorBinding(osg::Geometry::BIND_PER_VERTEX);
	}
	if (hasNormal())
	{
		setNormalArray(mNormalList);
		setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
	}
	addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, getPointNum()));

	getOrCreateStateSet()->setAttribute(new osg::Point(5.0f), osg::StateAttribute::ON);
}